﻿#include "HP_PullClient.h"
#include "HP_Buffer.h"

EnHandleResult HP_PullClient::OnPrepareConnect(ITcpClient* pSender, CONNID dwConnID, SOCKET socket)
{
	GetCallBack("OnPrepareConnect");
	lua_pushinteger(L, dwConnID);
	lua_pushinteger(L, socket);
	lua_call(L, 3, 1);
	return GetResult();
}

EnHandleResult HP_PullClient::OnConnect(ITcpClient* pSender, CONNID dwConnID)
{
	GetCallBack("OnConnect");
	lua_pushinteger(L, dwConnID);
	lua_call(L, 2, 1);
	return GetResult();
}

EnHandleResult HP_PullClient::OnReceive(ITcpClient* pSender, CONNID dwConnID, int iLength)
{
	GetCallBack("OnReceivePull");
	lua_pushinteger(L, dwConnID);
	lua_pushinteger(L, iLength);
	lua_call(L, 3, 1);
	return GetResult();
}

EnHandleResult HP_PullClient::OnReceive(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
	GetCallBack("OnReceive");
	lua_pushinteger(L, dwConnID);
	lua_pushlstring(L, (const char*)pData, iLength);
	lua_call(L, 3, 1);
	return GetResult();
}

EnHandleResult HP_PullClient::OnSend(ITcpClient* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
	GetCallBack("OnSend");
	lua_pushinteger(L, dwConnID);
	//lua_pushlightuserdata(L,(void*)pData);
	lua_pushinteger(L, iLength);
	lua_call(L, 3, 1);
	return GetResult();
}

EnHandleResult HP_PullClient::OnClose(ITcpClient* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
{
	GetCallBack("OnClose");
	lua_pushinteger(L, dwConnID);
	switch (enOperation) {
		CASE(SO_UNKNOWN)
			CASE(SO_ACCEPT)
			CASE(SO_CONNECT)
			CASE(SO_SEND)
			CASE(SO_RECEIVE)
			CASE(SO_CLOSE)
	}
	lua_pushinteger(L, iErrorCode);
	lua_call(L, 4, 1);
	return GetResult();
}

static BOOL luaL_optboolean(lua_State* L, int arg, BOOL def) {
	if (lua_isnoneornil(L, arg)) {
		return def;
	}
	return lua_toboolean(L, arg);
}

static ITcpPullClient* GetPullClient(lua_State* L) {
	lua_getuservalue(L, 1);
	ITcpPullClient* p = (ITcpPullClient*)lua_topointer(L, -1);
	lua_pop(L, 1);
	return p;
}

//ITcpClient
int SendSmallFile(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushboolean(L, cli->SendSmallFile(luaL_checkstring(L, 2),
		(LPWSABUF)luaL_optlstring(L, 3, nullptr, NULL),
		(LPWSABUF)luaL_optlstring(L, 4, nullptr, NULL)));
	return 1;
}

int SetSocketBufferSize(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	cli->SetSocketBufferSize((DWORD)luaL_checkinteger(L, 2));
	return 0;
}

int SetKeepAliveTime(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	cli->SetKeepAliveTime((DWORD)luaL_checkinteger(L, 2));
	return 0;
}

int SetKeepAliveInterval(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	cli->SetKeepAliveInterval((DWORD)luaL_checkinteger(L, 2));
	return 0;
}

int GetSocketBufferSize(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushinteger(L, cli->GetSocketBufferSize());
	return 1;
}

int GetKeepAliveTime(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushinteger(L, cli->GetKeepAliveTime());
	return 1;
}

int GetKeepAliveInterval(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushinteger(L, cli->GetKeepAliveInterval());
	return 1;
}
//IClient
int Start(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	BOOL r = cli->Start(luaL_checkstring(L, 2), (USHORT)luaL_checkinteger(L, 3), luaL_optboolean(L, 4, FALSE),
		luaL_optstring(L, 5, nullptr), (USHORT)luaL_optinteger(L, 6, 0U));
	lua_pushboolean(L, r);
	return 1;
}

int Stop(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	HP_mutex* mutex = *(HP_mutex**)lua_getextraspace(L);
	HP_UnlockMutex(mutex);
	BOOL r = cli->Stop();
	HP_LockMutex(mutex);
	lua_pushboolean(L, r);
	return 1;
}

//int Send(lua_State* L) {
//	ITcpPullClient* cli = GetPullClient(L);
//	size_t len;
//	BYTE* buf = (BYTE*)luaL_checklstring(L, 2, &len);
//	lua_pushboolean(L, cli->Send(buf, (int)len, (int)luaL_optinteger(L, 3, 0)));
//	return 1;
//}
//int SendPackets(lua_State* L){
//	ITcpPullClient* cli = GetPullClient(L);
//
//	return 0;
//}
int PauseReceive(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushboolean(L, cli->PauseReceive());
	return 1;
}

int Wait(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushboolean(L, cli->Wait((DWORD)luaL_optinteger(L, 2, INFINITE)));
	return 1;
}
//int SetExtra(lua_State* L){
//	ITcpPullClient* cli = GetPullClient(L);
//
//	return 0;
//}
//int GetExtra(lua_State* L){
//	ITcpPullClient* cli = GetPullClient(L);
//
//	return 0;
//}
int IsSecure(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushboolean(L, cli->IsSecure());
	return 1;
}

int HasStarted(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushboolean(L, cli->HasStarted());
	return 1;
}

int GetState(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	switch (cli->GetState()) {
		CASE(SS_STARTING)
			CASE(SS_STARTED)
			CASE(SS_STOPPING)
			CASE(SS_STOPPED)
	}
	return 1;
}

int GetLastError(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	switch (cli->GetLastError()) {
		CASE(SE_OK)
			CASE(SE_ILLEGAL_STATE)
			CASE(SE_INVALID_PARAM)
			CASE(SE_SOCKET_CREATE)
			CASE(SE_SOCKET_BIND)
			CASE(SE_SOCKET_PREPARE)
			CASE(SE_SOCKET_LISTEN)
			CASE(SE_CP_CREATE)
			CASE(SE_WORKER_THREAD_CREATE)
			CASE(SE_DETECT_THREAD_CREATE)
			CASE(SE_SOCKE_ATTACH_TO_CP)
			CASE(SE_CONNECT_SERVER)
			CASE(SE_NETWORK)
			CASE(SE_DATA_PROC)
			CASE(SE_DATA_SEND)
			CASE(SE_SSL_ENV_NOT_READY)
	}
	return 1;
}

int GetLastErrorDesc(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushstring(L, cli->GetLastErrorDesc());
	return 1;
}

int GetConnectionID(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushinteger(L, cli->GetConnectionID());
	return 1;
}

int GetLocalAddress(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	luaL_Buffer b;
	char* p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE);
	int len = LUAL_BUFFERSIZE;
	USHORT port;
	if (cli->GetLocalAddress(p, len, port)) {
		luaL_pushresultsize(&b, len - 1);
		lua_pushinteger(L, port);
		return 2;
	}
	return 0;
}

int GetRemoteHost(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	luaL_Buffer b;
	char* p = luaL_buffinitsize(L, &b, LUAL_BUFFERSIZE);
	int len = LUAL_BUFFERSIZE;
	USHORT port;
	if (cli->GetRemoteHost(p, len, port)) {
		luaL_pushresultsize(&b, len - 1);
		lua_pushinteger(L, port);
		return 2;
	}
	return 0;
}

int GetPendingDataLength(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	int v;
	cli->GetPendingDataLength(v);
	lua_pushinteger(L, v);
	return 1;
}

int IsPauseReceive(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	BOOL v;
	cli->IsPauseReceive(v);
	lua_pushboolean(L, v);
	return 1;
}

int IsConnected(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushboolean(L, cli->IsConnected());
	return 1;
}

int SetReuseAddressPolicy(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	static const char* const opts[] = { "RAP_NONE", "RAP_ADDR_ONLY", "RAP_ADDR_AND_PORT", NULL };
	//static const int optsnum[] = {RAP_NONE, RAP_ADDR_ONLY, RAP_ADDR_AND_PORT,};
	cli->SetReuseAddressPolicy(EnReuseAddressPolicy(luaL_checkoption(L, 2, "RAP_NONE", opts)));
	return 0;
}

int SetFreeBufferPoolSize(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	cli->SetFreeBufferPoolSize((DWORD)luaL_checkinteger(L, 2));
	return 0;
}

int SetFreeBufferPoolHold(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	cli->SetFreeBufferPoolHold((DWORD)luaL_checkinteger(L, 2));
	return 0;
}

int GetReuseAddressPolicy(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	switch (cli->GetReuseAddressPolicy()) {
		CASE(RAP_NONE)
			CASE(RAP_ADDR_ONLY)
			CASE(RAP_ADDR_AND_PORT)
	}
	return 1;
}

int GetFreeBufferPoolSize(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushinteger(L, cli->GetFreeBufferPoolSize());
	return 1;
}

int GetFreeBufferPoolHold(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	lua_pushinteger(L, cli->GetFreeBufferPoolHold());
	return 1;
}

static int Send(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	HP_Buffer* p = *(HP_Buffer**)luaL_checkudata(L, 2, "HP_Buffer");
	lua_pushboolean(L, cli->Send(p->GetPtr(), p->GetLen(), 0));
	return 1;
}

static int Fetch(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	HP_Buffer* p = *(HP_Buffer**)luaL_checkudata(L, 2, "HP_Buffer");
	int len = luaL_checkinteger(L, 3);
	lua_pushinteger(L, cli->Fetch(p->GetPtr(), len));
	p->m_len = len;
	p->m_bodylen = len;
	return 1;
}

static int Peek(lua_State* L) {
	ITcpPullClient* cli = GetPullClient(L);
	HP_Buffer* p = *(HP_Buffer**)luaL_checkudata(L, 2, "HP_Buffer");
	int len = luaL_checkinteger(L, 3);
	lua_pushinteger(L, cli->Peek(p->GetPtr(), len));
	return 1;
}

static int Creat_HP_PullClient(lua_State* L) {
	HP_PullClient* p = new HP_PullClient(L);
	HP_PullClient** ud = (HP_PullClient**)lua_newuserdata(L, sizeof(HP_PullClient*));
	*ud = p;
	lua_pushlightuserdata(L, (ITcpPullClient*)p->m_Client);
	lua_setuservalue(L, -2);
	luaL_setmetatable(L, "HP_PullClient");
	return 1;
}

static int Destroy_HP_PullClient(lua_State* L) {
	HP_PullClient* ud = *(HP_PullClient**)luaL_checkudata(L, 1, "HP_PullClient");
	ud->m_Client->Stop();
	delete ud;
	return 0;
}

#ifdef _WIN32
extern "C"
#endif // _WIN32
LUALIB_API
int luaopen_ghpsocket_pullclient(lua_State * L)
{
	luaL_Reg methods[] = {
		{"Fetch",Fetch},
		{"Peek",Peek},
		{"SendSmallFile",SendSmallFile},
		{"SetSocketBufferSize",SetSocketBufferSize},
		{"SetKeepAliveTime",SetKeepAliveTime},
		{"SetKeepAliveInterval",SetKeepAliveInterval},
		{"GetSocketBufferSize",GetSocketBufferSize},
		{"GetKeepAliveTime",GetKeepAliveTime},
		{"GetKeepAliveInterval",GetKeepAliveInterval},
		{"Start",Start},
		{"Stop",Stop},
		{"Send",Send},
		//{"SendPackets",SendPackets},
		{"PauseReceive",PauseReceive},
		{"Wait",Wait},
		//{"SetExtra",SetExtra},
		//{"GetExtra",GetExtra},
		{"IsSecure",IsSecure},
		{"HasStarted",HasStarted},
		{"GetState",GetState},
		{"GetLastError",GetLastError},
		{"GetLastErrorDesc",GetLastErrorDesc},
		{"GetConnectionID",GetConnectionID},
		{"GetLocalAddress",GetLocalAddress},
		{"GetRemoteHost",GetRemoteHost},
		{"GetPendingDataLength",GetPendingDataLength},
		{"IsPauseReceive",IsPauseReceive},
		{"IsConnected",IsConnected},
		{"SetReuseAddressPolicy",SetReuseAddressPolicy},
		{"SetFreeBufferPoolSize",SetFreeBufferPoolSize},
		{"SetFreeBufferPoolHold",SetFreeBufferPoolHold},
		{"GetReuseAddressPolicy",GetReuseAddressPolicy},
		{"GetFreeBufferPoolSize",GetFreeBufferPoolSize},
		{"GetFreeBufferPoolHold",GetFreeBufferPoolHold},
		{NULL, NULL},
	};
	//setvbuf(stdout, NULL, _IONBF, 0);
	luaL_newmetatable(L, "HP_PullClient");
	luaL_newlib(L, methods);
	lua_setfield(L, -2, "__index");
	lua_pushcfunction(L, Destroy_HP_PullClient);
	lua_setfield(L, -2, "__gc");
	lua_pop(L, 1);

	lua_pushcfunction(L, Creat_HP_PullClient);
	return 1;
}
